package  
{
	import as3isolib.display.IsoSprite;
	import com.smartfoxserver.v2.entities.variables.RoomVariable;
	import flash.display.Bitmap;
	import flash.display.DisplayObject;
	import flash.geom.Point;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import Util;
	import Globals;
	import AppState;
	import UI.*;
	import ButtonFunctions;
	import GameListData;
	
	import com.smartfoxserver.v2.entities.Room;
	
	import com.facebook.graph.Facebook;
	
	//import eDpLib.events.ProxyEvent;
	import com.greensock.TweenMax;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.KeyboardEvent;
	import flash.text.TextField;
	import flash.text.TextFieldType;
	
	/**
	 * ...
	 * @author Bryan Keiren & Sander van Katwijk
	 */
	public class Engine extends Sprite
	{
		
		static private var m_Singleton:Engine = null;
		static public function Get():Engine		{	return m_Singleton;		}
		
		// Console object.
		static private var m_Console:TextField = null;
		static private var m_NumPrints:int = 0;
		static public function printf(a_Msg:String):void
		{
			if (m_Console.numLines > 25)
			{
				m_Console.text = m_Console.text.substr(m_Console.getLineText(0).length);
			}
			m_Console.appendText(m_NumPrints++ + "> " + a_Msg + "\n");	// Output text to the console.
			m_Console.scrollV += 50;					// Scroll down to show the latest message.
			
			trace("> " + a_Msg + "\n");
		}
		
		private var m_State:int = AppState.MENU;
		public var m_Menu:Menu = new Menu();
		
		// List of data of the available games. Is constructed from data received from the server.
		public var m_GamesList:Vector.<GameListData> = new Vector.<GameListData>();
		
		[Embed(source = "/../lib/BG.png")] public static const BackgroundImage:Class;
		private var m_Background:Bitmap = new BackgroundImage as Bitmap;
		
		[Embed(source = "/../lib/list_bg.png")] public static const ListBackgroundImage:Class;
		private var m_ListBackground:Bitmap = new ListBackgroundImage as Bitmap;
		
		[Embed(source = "/../lib/buttons_bg.png")] public static const ButtonBackgroundImage:Class;
		private var m_ButtonBackground:Bitmap = new ButtonBackgroundImage as Bitmap;
		
		public var m_SelectedGameTextField:TextField = new TextField();
		
		// Facebook.
		private var APP_ID:String = "153169421448588";
		private var myUID:String;	// User's facebook UID string.
		private var myUsername:String;	// User's facebook username string.
		private var m_UseFacebook:Boolean = false;
		
		public function Engine():void
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e:Event = null):void
		{
			m_Singleton = this;
			
			// If init was called because it was added as an event listener, remove it now to make sure it doesn't get called again.
			removeEventListener(Event.ADDED_TO_STAGE, init);
			
			//m_UseFacebook = true;
			if (m_UseFacebook)
			{
				// Facebook initialisation.
				Facebook.init(APP_ID, onFacebookInit);
			}
			
			// Add the background.
			addChild(m_Background);
			
			// Add the list background.
			addChild(m_ListBackground);
			m_ListBackground.x = 40;
			m_ListBackground.y = 100;
			m_ListBackground.visible = false;
			m_ListBackground.rotationY = -10;
			
			// Add the button background.
			addChild(m_ButtonBackground);
			m_ButtonBackground.x = 540;
			m_ButtonBackground.y = 349;
			m_ButtonBackground.visible = false;
			m_ButtonBackground.rotationY = 15;
			
			// Add the textfield that will display which game has been selected.
			addChild(m_SelectedGameTextField);
			m_SelectedGameTextField.x = 500;
			m_SelectedGameTextField.y = 105;
			m_SelectedGameTextField.z = 10;
			m_SelectedGameTextField.width = 800 - m_SelectedGameTextField.x;
			m_SelectedGameTextField.text = "> No session selected";
			m_SelectedGameTextField.textColor = 0xffffff;
			m_SelectedGameTextField.setTextFormat(Globals.Text_Format_Consolas20_AlignLeft);
			m_SelectedGameTextField.visible = false;
			m_SelectedGameTextField.rotationY = 15;
			m_SelectedGameTextField.selectable = false;
			
			// Create the debug console. ALWAYS DO THIS FIRST.
			createConsole();
			
			var messageHandler:MessageHandler = new MessageHandler();
			messageHandler.init();
			
			// Create and initialize the game class.
			var game:Game = new Game();
			game.init();
			
			// Create the main menu.
			createMenu();
			
			// Add an event listener that is called each time a frame is rendered.
			stage.addEventListener(Event.ENTER_FRAME, gameIteration);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
			stage.addEventListener(KeyboardEvent.KEY_UP, onTildeKey);
		}
		
		private function onFacebookInit(success:Object, fail:Object):void
		{
			if (success)
			{
				myUID = success.uid;
				Facebook.api('/me', onFacebookLoadUserDetails);
				Engine.printf("Facebook initialised and already logged, fetching user details");
			}
			else
			{
				Engine.printf("Facebook initialised and not yet logged in, attempting now");
				var opts:Object = { scope:"user_photos" };
				Facebook.login(onFacebookLogin, opts);
			}
		}
		
		private function onTildeKey(evt:KeyboardEvent):void
		{
			if (evt.keyCode == 192)	// 192 = ` (Tilde key)
			{
				m_Console.visible = !m_Console.visible;
			}
		}
		
		protected function onFacebookLogin(success:Object, fail:Object):void
		{
			if (success)
			{
				myUID = success.uid;
				Facebook.api('/me', onFacebookLoadUserDetails);
				Engine.printf("Facebook logged in, fetching user details");
			}
			else 
			{
				Engine.printf("Facebook login failed");
			}
		}
		
		protected function onFacebookLoadUserDetails(success:Object, fail:Object):void
		{
			if (success)
			{
				if (success.hasOwnProperty("name"))
				{
					myUsername = success.name;
					Engine.printf("Facebook user name retrieved: '" + myUsername + "'");
					Globals.UserName_InputField.text = myUsername;
					Globals.UserName_InputField.setTextFormat(Globals.Text_Format_Consolas25_Centered);
				}
				else
				{
					Engine.printf("Facebook user name not retrieved");
				}
			}
		}
		
		private function onMouseMove(evt:MouseEvent):void
		{
			if (m_State != AppState.GAME)
			{
				root.transform.perspectiveProjection.projectionCenter = new Point((evt.stageX / 4) + (stage.width / 2), 
																				(evt.stageY / 4) + (stage.height / 2));
			}
			else
			{
				root.transform.perspectiveProjection.projectionCenter = new Point((stage.width / 2), 
																				  (stage.height / 2));
			}
		}
		
		private function createConsole():void
		{
			if (m_Console == null)
			{
				m_Console = new TextField();
				m_Console.x = 0;
				m_Console.y = 0;
				m_Console.width = 800;
				m_Console.height = 400;
				m_Console.mouseEnabled = false;
				m_Console.visible = false;
			}
			stage.addChild(m_Console);
		}
		
		private function createMenu():void
		{
			if (m_Menu == null)
			{
				m_Menu = new Menu();
			}
			
			// Log in page.
			var page:Page = new Page();
			
				// Global textfield. Is used to get the user to input a username.
				addChild(Globals.UserName_InputField);
				Globals.UserName_InputField.x = 275;
				Globals.UserName_InputField.y = 200;
				Globals.UserName_InputField.width = 250;
				Globals.UserName_InputField.height = 38;
				Globals.UserName_InputField.border = true;
				Globals.UserName_InputField.borderColor = 0xffffff;
				Globals.UserName_InputField.condenseWhite = true;
				Globals.UserName_InputField.focusRect = true;
				Globals.UserName_InputField.textColor = 0xffffff;
				Globals.UserName_InputField.backgroundColor = 0x333333;
				Globals.UserName_InputField.background = true;
				Globals.UserName_InputField.type = TextFieldType.INPUT;
				Globals.UserName_InputField.setTextFormat(Globals.Text_Format_Consolas25_Centered);
				Globals.UserName_InputField.addEventListener(KeyboardEvent.KEY_UP, ButtonFunctions.LogInOnEnterKey);
				Globals.UserName_InputField.maxChars = 16;
				Globals.UserName_InputField.condenseWhite = true;
				Globals.UserName_InputField.multiline = false;
				Globals.UserName_InputField.restrict = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";
				
				// Login button.
				var button:Button = new Button("LogIn", ButtonFunctions.LogIn, null, null, null);
				button.setX(300);
				button.setY(300);
				button.setWidth(200);
				button.setHeight(38);
				button.text.text = "_Log In";
				button.text.setTextFormat(Globals.Text_Format_Consolas25_Centered);
				button.data = Globals.UserName_InputField;
				page.addButton(button);
				m_Menu.addPage(page);
			
			// Lobby page.
			page = new Page();
			
				addChild(Globals.CurrentHighscore_Textfield);
				Globals.CurrentHighscore_Textfield.x = 50;
				Globals.CurrentHighscore_Textfield.y = 25;
				Globals.CurrentHighscore_Textfield.width = 700;
				Globals.CurrentHighscore_Textfield.height = 100;
				Globals.CurrentHighscore_Textfield.selectable = false;
				Globals.CurrentHighscore_Textfield.mouseEnabled = false;
				Globals.CurrentHighscore_Textfield.textColor = 0xffffff;
				Globals.CurrentHighscore_Textfield.visible = false;
				Globals.CurrentHighscore_Textfield.rotationY = -5;
				Globals.CurrentHighscore_Textfield.text = "You do not have a highscore yet.";
				Globals.CurrentHighscore_Textfield.setTextFormat(Globals.Text_Format_Consolas25_Centered);
				
				// Join session button.
				button = new Button("JoinSession", ButtonFunctions.JoinGame, null, null, null);
				button.setX(550);
				button.setY(450);
				button.setWidth(200);
				button.setHeight(38);
				button.text.text = "_Join session";
				button.text.setTextFormat(Globals.Text_Format_Consolas20_AlignLeft);
				button.deactivate();
				button.rotationY = 15;
				button.text.rotationY = 15;
				button.z = -10;
				button.text.z = -15;			
				page.addButton(button);
				
				// New game button.
				button = new Button("NewSession", ButtonFunctions.NewGame, null, null, null);
				button.setX(550);
				button.setY(405);
				button.setWidth(200);
				button.setHeight(38);
				button.text.text = "_New session";
				button.text.setTextFormat(Globals.Text_Format_Consolas20_AlignLeft);
				button.rotationY = 15;
				button.text.rotationY = 15;
				button.z = -10;
				button.text.z = -15;
				page.addButton(button);
				
				// Refresh list button.
				button = new Button("Refresh", ButtonFunctions.RefreshGameList);
				button.setX(550);
				button.setY(360);
				button.setWidth(200);
				button.setHeight(38);
				button.text.text = "_Refresh list";
				button.text.setTextFormat(Globals.Text_Format_Consolas20_AlignLeft);
				button.rotationY = 15;
				button.text.rotationY = 15;
				button.z = -10;
				button.text.z = -15;
				page.addButton(button);
				
				m_Menu.addPage(page);
				
			// Game page.
			page = new Page();
				
				// Exit game button.
				button = new Button("ExitSession", ButtonFunctions.ExitGame, null, null, null);
				button.setX(550);
				button.setY(500);
				button.setWidth(200);
				button.setHeight(38);
				button.text.text = "_Exit";
				button.text.setTextFormat(Globals.Text_Format_Consolas20_AlignLeft);
				button.z = -10;
				button.text.z = -15;
				page.addButton(button);
				
				addChild(Globals.Ingame_Score_TextField);
				Globals.Ingame_Score_TextField.x = 0;
				Globals.Ingame_Score_TextField.y = 400;
				Globals.Ingame_Score_TextField.width = 250;
				Globals.Ingame_Score_TextField.height = 100;
				Globals.Ingame_Score_TextField.autoSize = TextFieldAutoSize.LEFT;
				Globals.Ingame_Score_TextField.textColor = 0xffffff;
				//Globals.Ingame_Score_TextField.backgroundColor = 0x333333;
				//Globals.Ingame_Score_TextField.background = true;
				//Globals.Ingame_Score_TextField.border = true;
				//Globals.Ingame_Score_TextField.borderColor = 0xffffff;
				Globals.Ingame_Score_TextField.mouseEnabled = false;
				
				m_Menu.addPage(page);
		}
		
		public function getAppState():int
		{
			return m_State;
		}
		
		public function updateSessionList():void
		{
			var room:Room = MessageHandler.Get().m_SFS.getRoomByName(Globals.Lobby_Room_Name);
			var roomVars:Array = room.getVariables();
			
			// Clear the game list data.
			var gamelistdatasize:int = m_GamesList.length;
			for (var i:int = 0; i < gamelistdatasize; ++i)
			{
				m_GamesList.pop();
			}
				
			for each (var obj:RoomVariable in roomVars)
			{
				var varName:String = obj.getStringValue();
				
				if (varName != null)
				{				
					// If the variable starts with "Session", it is a game session name.
					if (Util.strStartsWith(varName, "Session"))
					{
						var roomFromName:Room = MessageHandler.Get().m_SFS.getRoomByName(varName);
						if (roomFromName != null)
						{
							var numPlayers:int = roomFromName.userCount;
							m_GamesList.push(new GameListData(varName, numPlayers)); 
						}
					}
				}
			}
			
			// Clear the button list.
			var page:Page = m_Menu.getPage(1);
			var buttons:Vector.<Button> = page.getButtons();
			while (buttons.length > 3)
			{
				page.popButton();
			}
			
			// Add new buttons.
			i = 0;
			for each (var obj2:GameListData in m_GamesList)
			{
				var button:Button = new Button("Game#" + i, ButtonFunctions.SetSelectedGame, null, null, null, ButtonFunctions.JoinGame, 1);
				button.setX(50);
				button.setY(150 + i * 45);
				button.setWidth(400);
				button.setHeight(38);
				button.text.text = "(" + obj2.m_NumPlayers + "/4 players) > " + obj2.m_Name;
				button.text.setTextFormat(Globals.Text_Format_Consolas15_AlignLeft);
				button.data = obj2.m_Name;
				button.rotationY = -10;
				button.text.rotationY = -10;
					
				page.addButton(button);
				
				++i;
			}
		}
		
		// This function is called each time a new frame is rendered. At the end of this function, it renders another frame.
		// So in effect, this is a loop.
		private function gameIteration(event:Event):void
		{
			Globals.updateTime();
			
			switch (m_State)
			{
				case AppState.MENU:
				{
					//Engine.printf("MENU");
					break;
				}
				case AppState.LOBBY:
				{
					//Engine.printf("LOBBY");
					break;
				}
				case AppState.GAME:
				{
					//Engine.printf("GAME");
					Game.Get().update();
					Game.Get().render();
					break;
				}
			}
			
		}
		
		public function SwitchAppState(a_State:int):void
		{
			trace("Switching app state");
			var team:Team;
			switch (a_State)
			{
				case AppState.MENU:
				{
					m_Menu.enable();
					m_Menu.setPage(0);
					Game.Get().disable();
					Globals.UserName_InputField.visible = true;
					Globals.Ingame_Score_TextField.visible = false;
					Globals.CurrentHighscore_Textfield.visible = false;
					m_ListBackground.visible = false;
					m_ButtonBackground.visible = false;
					m_SelectedGameTextField.visible = false;
					Globals.EndOfGame_Textfield.visible = false;
					break;
				}
				case AppState.LOBBY:
				{
					m_Menu.enable();
					m_Menu.setPage(1);
					Game.Get().disable();
					Globals.UserName_InputField.visible = false;
					Globals.EndOfGame_Textfield.visible = false;
					Globals.Ingame_Score_TextField.visible = false;
					Globals.CurrentHighscore_Textfield.visible = true;
					m_ListBackground.visible = true;
					m_ButtonBackground.visible = true;
					m_SelectedGameTextField.visible = true;
					m_SelectedGameTextField.text = "> No session selected";
					m_SelectedGameTextField.setTextFormat(Globals.Text_Format_Consolas20_AlignLeft);
					Globals.Selected_Game_Name = "";	// The data passed to this function is assumed to be of type String.
					Globals.Selected_Game_Bool = false;
					var JoinSessionBtn:Button = m_Menu.getPage(1).getButton("JoinSession");
					if (JoinSessionBtn)
					{
						JoinSessionBtn.deactivate();
					}
					
					for each (team in Team.getTeams())
					{
						team.showPlayerNames(false);
					}
					
					// Request an update for the current highscore.
					MessageHandler.Get().sendExtensionRequest("gethighscore", null);
					
					updateSessionList();
					break;
				}
				case AppState.GAME:
				{
					//removeChild(m_Background);
					//m_Menu.disable();
					m_Menu.setPage(2);
					Game.Get().enable();
					m_ListBackground.visible = false;
					m_ButtonBackground.visible = false;
					m_SelectedGameTextField.visible = false;
					Globals.Ingame_Score_TextField.visible = true;
					Globals.CurrentHighscore_Textfield.visible = false;
					
					for each (team in Team.getTeams())
					{
						team.showPlayerNames(true);
					}
					break;
				}
			}
			m_State = a_State;
		}
	}

}